/** @file

  Copyright (c) 2004  - 2019, Intel Corporation. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

Module Name:

  MemoryCallback.c

Abstract:

  EFI 2.0 PEIM to provide the platform support functionality on the Bridgeport.

--*/

#include "PlatformEarlyInit.h"


VOID
UpdateDefaultSetupValue (
  IN  EFI_PLATFORM_INFO_HOB       *PlatformInfo
  )
{
return;
}

/**
  PEI termination callback.

  @param PeiServices         General purpose services available to every PEIM.
  @param NotifyDescriptor    Not uesed.
  @param Ppi                 Not uesed.

  @retval EFI_SUCCESS        If the interface could be successfully
                             installed.

**/
EFI_STATUS
EFIAPI    
EndOfPeiPpiNotifyCallback (
  IN CONST EFI_PEI_SERVICES           **PeiServices,
  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
  IN VOID                       *Ppi
  )
{
  EFI_STATUS                  Status;
  UINT64                      LowUncableBase;
  EFI_PLATFORM_INFO_HOB       *PlatformInfo;
  UINT32                      HecBaseHigh;
  EFI_BOOT_MODE               BootMode;
  EFI_PEI_HOB_POINTERS        Hob;

  Status = (*PeiServices)->GetBootMode(
                             PeiServices,
                             &BootMode
                             );

  ASSERT_EFI_ERROR (Status);

  //
  // Set the some PCI and chipset range as UC
  // And align to 1M at leaset
  //
  Hob.Raw = GetFirstGuidHob (&gEfiPlatformInfoGuid);
  ASSERT (Hob.Raw != NULL);
  PlatformInfo = GET_GUID_HOB_DATA(Hob.Raw);

  UpdateDefaultSetupValue (PlatformInfo);

  DEBUG ((EFI_D_ERROR, "Memory TOLM: %X\n", PlatformInfo->MemData.MemTolm));
  DEBUG ((EFI_D_ERROR, "PCIE OSBASE: %lX\n", PlatformInfo->PciData.PciExpressBase));
  DEBUG (
    (EFI_D_ERROR,
    "PCIE   BASE: %lX     Size : %X\n",
    PlatformInfo->PciData.PciExpressBase,
    PlatformInfo->PciData.PciExpressSize)
    );
  DEBUG (
    (EFI_D_ERROR,
    "PCI32  BASE: %X     Limit: %X\n",
    PlatformInfo->PciData.PciResourceMem32Base,
    PlatformInfo->PciData.PciResourceMem32Limit)
    );
  DEBUG (
    (EFI_D_ERROR,
    "PCI64  BASE: %lX     Limit: %lX\n",
    PlatformInfo->PciData.PciResourceMem64Base,
    PlatformInfo->PciData.PciResourceMem64Limit)
    );
  DEBUG ((EFI_D_ERROR, "UC    START: %lX     End  : %lX\n", PlatformInfo->MemData.MemMir0, PlatformInfo->MemData.MemMir1));

  LowUncableBase = PlatformInfo->MemData.MemMaxTolm;
  LowUncableBase &= (0x0FFF00000);

  if (BootMode != BOOT_ON_S3_RESUME) {
    //
    // In BIOS, HECBASE will be always below 4GB
    //
    HecBaseHigh = (UINT32) RShiftU64 (PlatformInfo->PciData.PciExpressBase, 28);
    ASSERT (HecBaseHigh < 16);
  }

  return Status;
}

/**
  Install Firmware Volume Hob's once there is main memory

  @param PeiServices       General purpose services available to every PEIM.
  @param NotifyDescriptor  Notify that this module published.
  @param Ppi               PPI that was installed.

  @retval EFI_SUCCESS     The function completed successfully.

**/
EFI_STATUS
EFIAPI
MemoryDiscoveredPpiNotifyCallback (
  IN CONST EFI_PEI_SERVICES           **PeiServices,
  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
  IN VOID                       *Ppi
  )
{
  EFI_STATUS                  Status;
  EFI_BOOT_MODE               BootMode;
  UINT32                      MaximumExtendedFunction;
  CPUID_VIR_PHY_ADDRESS_SIZE_EAX  Eax;
  UINT8                       CpuAddressWidth;
  UINT16                      Pm1Cnt;
  EFI_PEI_HOB_POINTERS        Hob;
  EFI_PLATFORM_INFO_HOB       *PlatformInfo;
  UINT32                      RootComplexBar;
  UINT32                      PmcBase;
  UINT32                      IoBase;
  UINT32                      IlbBase;
  UINT32                      SpiBase;
  UINT32                      MphyBase;

  //
  // Get Platform Info HOB
  //
  Hob.Raw = GetFirstGuidHob (&gEfiPlatformInfoGuid);
  ASSERT (Hob.Raw != NULL);
  PlatformInfo = GET_GUID_HOB_DATA(Hob.Raw);

  Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode);

  //
  // Check if user wants to turn off in PEI phase
  //
  if ((BootMode != BOOT_ON_S3_RESUME) && (BootMode != BOOT_ON_FLASH_UPDATE)) {
    CheckPowerOffNow();
  } else {
    Pm1Cnt  = IoRead16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT);
    Pm1Cnt &= ~B_PCH_ACPI_PM1_CNT_SLP_TYP;
    IoWrite16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT, Pm1Cnt);
  }

  //
  // Set PEI cache mode here
  //
  SetPeiCacheMode (PeiServices);

  //
  //  Pulish memory tyoe info
  //
  PublishMemoryTypeInfo ();

  //
  // Work done if on a S3 resume
  //
  if (BootMode == BOOT_ON_S3_RESUME) {
    //
    //Program the side band packet register to send a sideband message to Punit
    //To indicate that DRAM has been initialized and PUNIT FW base address in memory.
    //
    return EFI_SUCCESS;
  }

  RootComplexBar = MmPci32( 0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_RCBA ) & B_PCH_LPC_RCBA_BAR;
  BuildResourceDescriptorHob (
    EFI_RESOURCE_MEMORY_MAPPED_IO,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    RootComplexBar,
    0x1000
    );
  DEBUG ((EFI_D_INFO, "RootComplexBar     : 0x%x\n", RootComplexBar));

  PmcBase = MmPci32( 0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_PMC_BASE ) & B_PCH_LPC_PMC_BASE_BAR;
  BuildResourceDescriptorHob (
    EFI_RESOURCE_MEMORY_MAPPED_IO,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    PmcBase,
    0x1000
    );
  DEBUG ((EFI_D_INFO, "PmcBase            : 0x%x\n", PmcBase));

  IoBase = MmPci32( 0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_IO_BASE ) & B_PCH_LPC_IO_BASE_BAR;
  BuildResourceDescriptorHob (
    EFI_RESOURCE_MEMORY_MAPPED_IO,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    IoBase,
    0x4000
    );
  DEBUG ((EFI_D_INFO, "IoBase             : 0x%x\n", IoBase));

  IlbBase = MmPci32( 0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_ILB_BASE ) & B_PCH_LPC_ILB_BASE_BAR;
  BuildResourceDescriptorHob (
    EFI_RESOURCE_MEMORY_MAPPED_IO,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    IlbBase,
    0x1000
    );
  DEBUG ((EFI_D_INFO, "IlbBase            : 0x%x\n", IlbBase));

  SpiBase = MmPci32( 0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_SPI_BASE ) & B_PCH_LPC_SPI_BASE_BAR;
  BuildResourceDescriptorHob (
    EFI_RESOURCE_MEMORY_MAPPED_IO,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    SpiBase,
    0x1000
    );
  DEBUG ((EFI_D_INFO, "SpiBase            : 0x%x\n", SpiBase));

  MphyBase = MmPci32( 0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_MPHY_BASE ) & B_PCH_LPC_MPHY_BASE_BAR;
  BuildResourceDescriptorHob (
    EFI_RESOURCE_MEMORY_MAPPED_IO,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    MphyBase,
    0x100000
    );
  DEBUG ((EFI_D_INFO, "MphyBase           : 0x%x\n", MphyBase));

  //
  // Local APIC
  //
  BuildResourceDescriptorHob (
    EFI_RESOURCE_MEMORY_MAPPED_IO,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    LOCAL_APIC_ADDRESS,
    0x1000
  );
  DEBUG ((EFI_D_INFO, "LOCAL_APIC_ADDRESS : 0x%x\n", LOCAL_APIC_ADDRESS));

  //
  // IO APIC
  //
  BuildResourceDescriptorHob (
    EFI_RESOURCE_MEMORY_MAPPED_IO,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    IO_APIC_ADDRESS,
    0x1000
  );
  DEBUG ((EFI_D_INFO, "IO_APIC_ADDRESS    : 0x%x\n", IO_APIC_ADDRESS));

  //
  // Adding the PCIE Express area to the E820 memory table as type 2 memory.
  //
  BuildResourceDescriptorHob (
    EFI_RESOURCE_MEMORY_MAPPED_IO,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    PlatformInfo->PciData.PciExpressBase,
    PlatformInfo->PciData.PciExpressSize
    );
  DEBUG ((EFI_D_INFO, "PciExpressBase     : 0x%x\n", PlatformInfo->PciData.PciExpressBase));

  //
  // Adding the Flashpart to the E820 memory table as type 2 memory.
  //
  BuildResourceDescriptorHob (
    EFI_RESOURCE_FIRMWARE_DEVICE,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    FixedPcdGet32 (PcdFlashAreaBaseAddress),
    FixedPcdGet32 (PcdFlashAreaSize)
    );
  DEBUG ((EFI_D_INFO, "FLASH_BASE_ADDRESS : 0x%x\n", FixedPcdGet32 (PcdFlashAreaBaseAddress)));

  //
  // Create a CPU hand-off information
  //
  CpuAddressWidth = 32;
  AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaximumExtendedFunction, NULL, NULL, NULL);
  if (MaximumExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {
    AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &Eax.Uint32, NULL, NULL, NULL);
    CpuAddressWidth = (UINT8) (Eax.Bits.PhysicalAddressBits);
  }

  BuildCpuHob(CpuAddressWidth, 16);
  ASSERT_EFI_ERROR (Status);

  return Status;

}


EFI_STATUS
ValidateFvHeader (
  IN EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader
  )
{
  UINT16  *Ptr;
  UINT16  HeaderLength;
  UINT16  Checksum;

  //
  // Verify the header revision, header signature, length
  // Length of FvBlock cannot be 2**64-1
  // HeaderLength cannot be an odd number
  //
  if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
      (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
      (FwVolHeader->FvLength == ((UINT64) -1)) ||
      ((FwVolHeader->HeaderLength & 0x01) != 0)
      ) {
    return EFI_NOT_FOUND;
  }

  //
  // Verify the header checksum
  //
  HeaderLength  = (UINT16) (FwVolHeader->HeaderLength / 2);
  Ptr           = (UINT16 *) FwVolHeader;
  Checksum      = 0;
  while (HeaderLength > 0) {
    Checksum = *Ptr++;
    HeaderLength--;
  }

  if (Checksum != 0) {
    return EFI_NOT_FOUND;
  }

  return EFI_SUCCESS;
}
